package com.abc.config.memory;

import cn.hutool.core.util.ObjectUtil;
import com.abc.config.ChatMemoryConfig;
import com.abc.help.SessionHelper;
import com.abc.model.ChatMessageModel;
import com.abc.service.IdGeneratorService;
import com.abc.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Slf4j
@Component
public class MongodbChatMemory implements ChatMemory {

    @Autowired
    private MongodbChatMemoryRepository repository;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private ChatMemoryConfig chatMemoryConfig;

    @Autowired
    private IdGeneratorService idGeneratorService;
    

    /**
     * 生成Redis键名
     *
     * @param conversationId 对话ID
     * @return Redis键名
     */
    private String buildRedisKey(String conversationId) {
        return String.format(chatMemoryConfig.getPrefix(), SessionHelper.getUser(), conversationId);
    }

    @Override
    public void add(String conversationId, List<Message> messages) {
        if (ObjectUtil.isEmpty(messages)) {
            return;
        }

        String redisKey = buildRedisKey(conversationId);
        Integer maxMessages = chatMemoryConfig.getMaxMessages();

        try {
            // 保存到MongoDB并获取生成的消息模型（包含完整的ID和链路信息）
            List<ChatMessageModel> savedMessageModels = repository.saveAllAndReturn(conversationId, messages);

            // 将生成的消息模型添加到Redis列表的右端（最新消息在右边）
            List<Object> messageObjects = new ArrayList<>(savedMessageModels);
            redisUtil.rPushAllAndTrim(redisKey, messageObjects, maxMessages);

            // 设置Redis键的过期时间
            redisUtil.expire(redisKey, chatMemoryConfig.getCacheExpireDays(), TimeUnit.DAYS);

            log.debug("成功添加{}条消息到会话: {}，消息ID范围: {} - {}", 
                     savedMessageModels.size(), conversationId,
                     savedMessageModels.isEmpty() ? "无" : savedMessageModels.get(0).getMessageId(),
                     savedMessageModels.isEmpty() ? "无" : savedMessageModels.get(savedMessageModels.size() - 1).getMessageId());

        } catch (Exception e) {
            log.error("添加消息到会话失败: {}, 错误: {}", conversationId, e.getMessage(), e);
            // 即使Redis操作失败，也要保存到MongoDB
            repository.saveAll(conversationId, messages);
        }
    }

    @Override
    public List<Message> get(String conversationId) {
        String redisKey = buildRedisKey(conversationId);
        Integer maxMessages = chatMemoryConfig.getMaxMessages();

        try {
            // 先从Redis获取ChatMessageModel对象（获取所有消息，0到-1表示全部）
            List<Object> redisObjects = redisUtil.lRange(redisKey, 0, -1);

            if (redisObjects != null && !redisObjects.isEmpty()) {
                // Redis中有消息，先转换为ChatMessageModel列表
                List<ChatMessageModel> redisMessageModels = convertToMessageModels(redisObjects);

                if (redisMessageModels.size() >= maxMessages) {
                    log.info("从Redis获取到{}条消息，会话: {}", redisMessageModels.size(), conversationId);
                    return convertToMessages(redisMessageModels);
                }

                // Redis中消息不足maxMessages，需要从MongoDB补充
                int needMore = maxMessages - redisMessageModels.size();
                List<ChatMessageModel> mongoMessageModels = repository.findLatestMessageModelsByConversationId(conversationId, needMore);

                // 合并消息，去重（避免重复）
                List<ChatMessageModel> combinedMessageModels = mergeAndDeduplicateMessageModels(mongoMessageModels, redisMessageModels);

                // 限制最大数量
                if (combinedMessageModels.size() > maxMessages) {
                    combinedMessageModels = combinedMessageModels.subList(combinedMessageModels.size() - maxMessages, combinedMessageModels.size());
                }

                // 更新Redis缓存
                if (!combinedMessageModels.isEmpty()) {
                    updateRedisCache(redisKey, combinedMessageModels, maxMessages);
                }

                log.debug("从Redis+MongoDB获取到{}条消息，会话: {}", combinedMessageModels.size(), conversationId);
                return convertToMessages(combinedMessageModels);
            }

            // Redis中没有消息，从MongoDB获取
            List<ChatMessageModel> mongoMessageModels = repository.findLatestMessageModelsByConversationId(conversationId, maxMessages);

            if (!mongoMessageModels.isEmpty()) {
                // 将MongoDB中的消息缓存到Redis
                updateRedisCache(redisKey, mongoMessageModels, maxMessages);
                log.debug("从MongoDB获取到{}条消息并缓存到Redis，会话: {}", mongoMessageModels.size(), conversationId);
            } else {
                log.debug("会话{}没有找到任何消息", conversationId);
            }

            return convertToMessages(mongoMessageModels);

        } catch (Exception e) {
            log.error("获取会话消息失败: {}, 错误: {}", conversationId, e.getMessage(), e);
            try {
                List<ChatMessageModel> fallbackModels = repository.findLatestMessageModelsByConversationId(conversationId, maxMessages);
                return convertToMessages(fallbackModels);
            } catch (Exception mongoException) {
                log.error("从MongoDB获取消息也失败: {}, 错误: {}", conversationId, mongoException.getMessage(), mongoException);
                return new ArrayList<>();
            }
        }
    }

    @Override
    public void clear(String conversationId) {
        String redisKey = buildRedisKey(conversationId);

        try {
            // 清除Redis缓存
            redisUtil.delete(redisKey);
            log.debug("清除Redis缓存成功，会话: {}", conversationId);
        } catch (Exception e) {
            log.error("清除Redis缓存失败，会话: {}, 错误: {}", conversationId, e.getMessage(), e);
        }

        log.info("清除会话缓存: {}", conversationId);
    }

    /**
     * 将Object列表转换为ChatMessageModel列表
     *
     * @param objects Redis中获取的对象列表
     * @return ChatMessageModel列表
     */
    private List<ChatMessageModel> convertToMessageModels(List<Object> objects) {
        List<ChatMessageModel> messageModels = new ArrayList<>();
        for (Object obj : objects) {
            if (obj instanceof ChatMessageModel) {
                messageModels.add((ChatMessageModel) obj);
            }
        }
        return messageModels;
    }

    /**
     * 将ChatMessageModel列表转换为Message列表
     *
     * @param messageModels ChatMessageModel列表
     * @return Message列表
     */
    private List<Message> convertToMessages(List<ChatMessageModel> messageModels) {
        return messageModels.stream()
                .map(ChatMessageModel::toMessage)
                .filter(ObjectUtil::isNotNull)
                .collect(Collectors.toList());
    }

    /**
     * 合并并去重消息模型列表
     *
     * @param mongoModels MongoDB中的消息模型
     * @param redisModels Redis中的消息模型
     * @return 合并后的消息模型列表
     */
    private List<ChatMessageModel> mergeAndDeduplicateMessageModels(List<ChatMessageModel> mongoModels, List<ChatMessageModel> redisModels) {
        List<ChatMessageModel> combinedModels = new ArrayList<>(mongoModels);

        // 添加Redis中的消息（如果不重复）
        for (ChatMessageModel redisModel : redisModels) {
            boolean isDuplicate = combinedModels.stream()
                    .anyMatch(model -> model.getMessageId() != null 
                            && model.getMessageId().equals(redisModel.getMessageId()));
            if (!isDuplicate) {
                combinedModels.add(redisModel);
            }
        }

        return combinedModels;
    }

    /**
     * 更新Redis缓存
     *
     * @param redisKey Redis键
     * @param messageModels 消息模型列表
     * @param maxMessages 最大消息数量
     */
    private void updateRedisCache(String redisKey, List<ChatMessageModel> messageModels, Integer maxMessages) {
        try {
            redisUtil.delete(redisKey);
            List<Object> messageObjects = new ArrayList<>(messageModels);
            redisUtil.rPushAllAndTrim(redisKey, messageObjects, maxMessages);
            redisUtil.expire(redisKey, chatMemoryConfig.getCacheExpireDays(), TimeUnit.DAYS);
        } catch (Exception e) {
            log.error("更新Redis缓存失败，redisKey: {}, 错误: {}", redisKey, e.getMessage(), e);
        }
    }


}